// =================1. 对象方法中的 this===============
/**
 * 传统的函数定义方式中，this 的值取决于函数的调用方式，这经常导致 this 指向与预期不符，从而引发各种 bug。
 * ES6 引入的箭头函数，除了语法更简洁之外，最大的特点就是绑定了词法作用域的 this，
 * 即 this 的值取决于箭头函数定义的位置，而不是调用时的上下文。这一特性使得箭头函数成为解决 this 绑定问题的利器。
 */
const obj = {
    myName: 'lesong',
    getName: function() {
        // 在对象方法中使用普通函数，this 指向的是调用该方法的对象。但如果在方法内部还有嵌套函数，那么嵌套函数中的 this 就会指向全局对象（非严格模式下）或 undefined（严格模式下）。
        // 打印lesong
        console.log(this.myName)
        function init() {
            console.log(this.myName)
        }
        // 非严格模式下输出undefined，严格模式下会报错
        // 函数中的 this 就会指向全局对象（非严格模式下）或 undefined（严格模式下）。
        init()
        // 打印lesong
        init.call(this)
    },
    getName2: () => {
        // this 会绑定到定义时的上下文，也就是指向全局。
        // 打印为undefined
        console.log(this.myName)
        function init() {
            console.log(this.myName)
        }
        // 打印为undefined
        init()
    },
    getName3: function() {
        // 打印lesong
        console.log(this.myName)
        const init = () => {
            console.log(this.myName)
        }
        // 打印lesong
        init()
    }
}
obj.getName3()

function MyClass2 () {
    this.value = 10
    this.increment = () =>{
        this.value++
        console.log(this)
    }
}
MyClass2.prototype.getValue = function() {
    // console.log(this.value)
    return this.value
}
const instance2 = new MyClass2()
instance2.increment()
console.log(instance2.getValue())

const MyClass3 = () => {
    this.value = 10
    this.increment = () =>{
        this.value++
        console.log(this)
    }
}
// 报错Uncaught TypeError: MyClass3 is not a constructor
// 箭头函数如法作为构造函数，因为没有this
const instance3 = new MyClass3()
instance3.increment()
console.log(instance3.value)

// class MyClass {
//     value = 10
//     increment() {
//         this.value++
//         console.log(this)
//     }
// }
// const instance = new MyClass()
// instance.increment()
// console.log(instance.value)


// -------------5. 数组方法中的回调函数----------------
// 在 map、filter、reduce 等数组方法中，如果回调函数是普通函数，this 的指向会根据函数的调用方式而定，通常不是我们期望的上下文。
const myObject = {
    data: [1,2,3],
    getData: function() {
        const result = this.data.map(function(item) {
            // this指向全局或者是undefined
            console.log(this)
            return item * this.num
        })
        return result
    },
    num: 2
}
// 打印出[NaN,NaN,NaN]
myObject.getData()

const myObject2 = {
    data: [1,2,3],
    getData: function() {
        // // 方式一：绑定this
        // const result = this.data.map(function(item) {
        //     return item * this.num
        // }, this) //绑定this

        // 方式二：使用箭头函数
        const result = this.data.map((item) => item * this.num)
        return result
    },
    num: 2
}
// 打印出[2,4,6]
myObject2.getData()

// -------------------6. 延迟执行函数中的 this (例如 setTimeout、setInterval)----------------
// 在 setTimeout 或 setInterval 的回调函数中，this 通常指向全局对象（非严格模式）或 undefined（严格模式）。
const timerOutObj = {
    myName: 'lesong',
    getName: function() {
        setTimeout(function() {
            console.log(this.myName) // this指向全局或者是undefined
        }, 1000)
    }
}
// 使用箭头函数
const timerOutObj2 = {
    myName: 'lesong',
    getName: function() {
        setTimeout(() => {
            console.log(this.myName) //打印出lesong this指向timerOutObj2
        }, 1000)
    }
}
